// Copyright (c) 2010 Omer Goshen
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "TransformWidget.h"
#include "core/Object.h"

using namespace Ogre;

const int RENDER_QUEUE_CENTER = 71;
const int RENDER_QUEUE_PLANES = 70;

TransformWidget*				TransformWidget::mInstance = NULL;
bool 			 				TransformWidget::mInit = false;
bool 			 				TransformWidget::mTransforming = false;
TransformWidget::EntityAxisMap 	TransformWidget::mEntAxisMap;

TransformWidget* TransformWidget::getSingletonPtr( void )
{
	if ( !mInstance )
		{
			mInstance = new TransformWidget(App::getSingletonPtr()->getSceneManager());
		}
	return mInstance;
}

TransformWidget& TransformWidget::getInstance( void )
{
	if ( !mInstance )
		{
			mInstance = new TransformWidget(App::getSingletonPtr()->getSceneManager());
		}
	return *mInstance;
}

TransformWidget::TransformWidget(SceneManager* sceneMgr) :
	mSceneMgr(sceneMgr),
	mGo(0),
	mCamera(0),
	mNode(0),
	mTransNode(0),
	mTransVec(Vector3::ZERO),
	mActiveAxis(-1),
	mOffset(Vector3::ZERO),
	mMode(MOVE),
	mTS(WORLD)
{
	mCamera = App::getSingletonPtr()->getCamera();

	if (!TransformWidget::mInit)
		_setup();

	const Real S = 5.0f;
	const Real R = S/4+.1;

	Root::getSingletonPtr()->addFrameListener(this);

	// Manually create the scenenode as it will be attached to an overlay...
//	mNode = mSceneMgr->createSceneNode("TransformWidget");
	mNode = new SceneNode(mSceneMgr, "TransformWidget");
	mNode->setUserAny(Any(this));

	mRotateNodes.clear();
	mScaleNodes.clear();
	mMoveNodes.clear();
	mLineNodes.clear();
	
	Entity* ent;
	SceneNode* node;

	ent = mSceneMgr->createEntity("Center_Box");
	mEntities.push_back(ent);
	ent->setRenderQueueGroup(RENDER_QUEUE_CENTER);
	node = mNode->createChildSceneNode("Center_Box");
	node->attachObject(ent);
	mEntAxisMap[ent] = X_AXIS | Y_AXIS | Z_AXIS;

	//{{{ X-Axis
	ent = mSceneMgr->createEntity("X_Cone");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("X_Cone");
	node->attachObject(ent);
	node->setPosition(S,0,0);
	node->roll(Degree(-90));
	node->setVisible(mMode==MOVE);
	mMoveNodes.push_back(node);
	mEntAxisMap[ent] = X_AXIS;

	ent = mSceneMgr->createEntity("X_Box");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("X_Box");
	node->attachObject(ent);
	node->setPosition(S,0,0);
	node->setVisible(mMode==SCALE);
	mScaleNodes.push_back(node);
	mEntAxisMap[ent] = X_AXIS;

	ent = mSceneMgr->createEntity("X_Cylinder", "X_Cylinder");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("X_Cylinder");
	node->attachObject(ent);
	node->setVisible(mMode==ROTATE);
	mRotateNodes.push_back(node);
	mEntAxisMap[ent] = X_AXIS;

	ent = mSceneMgr->createEntity("X_Line");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("X_Line");
	node->attachObject(ent);
	node->setPosition(S/2,0,0);
	node->scale(S*Vector3::UNIT_SCALE);
	mLineNodes.push_back(node);
	mEntAxisMap[ent] = X_AXIS;
	//}}}

	//{{{ Y-Axis
	ent = mSceneMgr->createEntity("Y_Cone");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("Y_Cone");
	node->attachObject(ent);
	node->setPosition(0,S,0);
	node->setVisible(mMode==MOVE);
	mMoveNodes.push_back(node);
	mEntAxisMap[ent] = Y_AXIS;

	ent = mSceneMgr->createEntity("Y_Box");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("Y_Box");
	node->attachObject(ent);
	node->setPosition(0,S,0);
	node->setVisible(mMode==SCALE);
	mScaleNodes.push_back(node);
	mEntAxisMap[ent] = Y_AXIS;

	ent = mSceneMgr->createEntity("Y_Cylinder", "Y_Cylinder");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("Y_Cylinder");
	node->attachObject(ent);
	node->setVisible(mMode==ROTATE);
	Quaternion q;
	q.FromAngleAxis(Degree(90), Vector3::UNIT_Z);
	node->setOrientation(q);
	mRotateNodes.push_back(node);
	mEntAxisMap[ent] = Y_AXIS;

	ent = mSceneMgr->createEntity("Y_Line");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("Y_Line");
	node->attachObject(ent);
	node->setPosition(0,S/2,0);
	node->scale(S*Vector3::UNIT_SCALE);
	mLineNodes.push_back(node);
	mEntAxisMap[ent] = Y_AXIS;
	//}}}

	//{{{ Z-Axis
	ent = mSceneMgr->createEntity("Z_Cone");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("Z_Cone");
	node->attachObject(ent);
	node->setPosition(0,0,S);
	node->pitch(Degree(90));
	node->setVisible(mMode==MOVE);
	mMoveNodes.push_back(node);
	mEntAxisMap[ent] = Z_AXIS;

	ent = mSceneMgr->createEntity("Z_Box");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("Z_Box");
	node->attachObject(ent);
	node->setPosition(0,0,S);
	node->setVisible(mMode==SCALE);
	mScaleNodes.push_back(node);
	mEntAxisMap[ent] = Z_AXIS;

	ent = mSceneMgr->createEntity("Z_Cylinder", "Z_Cylinder");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("Z_Cylinder");
	node->attachObject(ent);
	node->setVisible(mMode==ROTATE);
	q.FromAngleAxis(Degree(90), Vector3::UNIT_X);
	node->setOrientation(q);
	mRotateNodes.push_back(node);
	mEntAxisMap[ent] = Z_AXIS;

	ent = mSceneMgr->createEntity("Z_Line");
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("Z_Line");
	node->attachObject(ent);
	node->setPosition(0,0,S/2);
	node->scale(S*Vector3::UNIT_SCALE);
	mLineNodes.push_back(node);
	mEntAxisMap[ent] = Z_AXIS;
	//}}}

	ent = mSceneMgr->createEntity("XY");
	ent->setRenderQueueGroup(RENDER_QUEUE_PLANES);
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("XY");
	node->attachObject(ent);
	node->setPosition(R,R,0);
	node->scale(S/2*Vector3::UNIT_SCALE);
	node->setVisible(mMode==MOVE);
	mMoveNodes.push_back(node);
	mEntAxisMap[ent] = X_AXIS | Y_AXIS;

	ent = mSceneMgr->createEntity("XZ");
	ent->setRenderQueueGroup(RENDER_QUEUE_PLANES);
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("XZ");
	node->attachObject(ent);
	node->setPosition(R,0,R);
	node->scale(S/2*Vector3::UNIT_SCALE);
	node->setVisible(mMode==MOVE);
	mMoveNodes.push_back(node);
	mEntAxisMap[ent] = X_AXIS | Z_AXIS;

	ent = mSceneMgr->createEntity("YZ");
	ent->setRenderQueueGroup(RENDER_QUEUE_PLANES);
	mEntities.push_back(ent);
	node = mNode->createChildSceneNode("YZ");
	node->attachObject(ent);
	node->setPosition(0,R,R);
	node->scale(S/2*Vector3::UNIT_SCALE);
	node->setVisible(mMode==MOVE);
	mMoveNodes.push_back(node);
	mEntAxisMap[ent] = Y_AXIS | Z_AXIS;


	for (std::vector<Entity*>::iterator it=mEntities.begin(); it!=mEntities.end(); ++it)
		{
			ent = static_cast<Entity*>(*it);
			ent->setCastShadows(false);
			ent->setPolygonModeOverrideable(false);

			MaterialPtr mat = ent->getSubEntity(0)->getMaterial();
//			mat->setDepthCheckEnabled(false);
//			mat->setDepthWriteEnabled(false);
//			mat->setCullingMode(CULL_NONE);
//			mat->setSelfIllumination(.01f, .01f, .01f);
//			ent->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY);
//			ent->setRenderQueueGroup(Ogre::RENDER_QUEUE_9);
		}


	//{{{ Circles
	ManualObject * circle = mSceneMgr->createManualObject("TFW_Circle");
	float const accuracy = 35;
	float const radius = 6.1;
	ColourValue c = ColourValue(.5,.5,.5,.75);

	circle->begin("VertexColour/Flat/AlphaBlendedNoCullDepthOff", RenderOperation::OT_LINE_STRIP);
//	circle->begin("FlatVertexColour/CullNone", RenderOperation::OT_LINE_STRIP);
//	circle->begin("PlainColorNoCull", RenderOperation::OT_LINE_STRIP);

	unsigned point_index = 0;
	for (float theta = 0; theta <= 2 * Math::PI; theta += Math::PI / accuracy)
		{
			circle->position(radius * cos(theta), 0, radius * sin(theta));
			circle->colour(c);
			circle->index(point_index++);
		}
	circle->index(0);

	circle->end();
	circle->setCastShadows(false);
	circle->setVisible(mMode==ROTATE);
	mCircleNode = mNode->createChildSceneNode("CircleNode");
	mCircleNode->attachObject(circle);
	mCircleNode->pitch(Degree(90));


	c = ColourValue(.5,.5,.5,.5);
	mCircle = mSceneMgr->createManualObject("TFW_Circle2");
	mCircle->begin("VertexColour/Flat/AlphaBlended", RenderOperation::OT_TRIANGLE_STRIP);
	point_index = 0;
	float deltaAngle = (Ogre::Math::TWO_PI / accuracy);
	mCircle->position(0,.25,0);
	mCircle->colour(c);
//		mCircle->normal(Ogre::Vector3::NEGATIVE_UNIT_Y);
	point_index++;
	for (int j=0; j<=accuracy; j++)
		{
			float x0 = radius * cosf(j*deltaAngle);
			float z0 = radius * sinf(j*deltaAngle);

			mCircle->position(x0, 0.25f, z0);
			if (j!=accuracy)
				{
					mCircle->index(0);
					mCircle->index(point_index);
					mCircle->index(point_index+1);
				}
			point_index++;
		}

	mCircle->end();
	mCircle->setCastShadows(false);
	mCircle->setDynamic(true);
	mCircle->setVisible(false);
	mNode->attachObject(mCircle);
	//}}}

	//{{{ Helpers
	mLineHelpers = mNode->createChildSceneNode("LineHelpers");
	ManualObject* mo =  mSceneMgr->createManualObject("LineHelper_X");
	mo->setCastShadows(false);
	mo->setDynamic(true);
	mo->estimateVertexCount(2);
	mo->estimateIndexCount(2);

	mo->begin("VertexColour/Flat/AlphaBlended/NoCull", Ogre::RenderOperation::OT_LINE_LIST);
	mo->position(10000,0,0);
	mo->colour(ColourValue(1,.1,.1,.5));
	mo->position(-10000,0,0);
	mo->colour(ColourValue(1,.1,.1,.5));
	mo->end();

	mLineHelpers->attachObject(mo);

	mo =  mSceneMgr->createManualObject("LineHelper_Y");
	mo->setCastShadows(false);
	mo->setDynamic(true);
	mo->estimateVertexCount(2);
	mo->estimateIndexCount(2);

	mo->begin("VertexColour/Flat/AlphaBlended/NoCull", Ogre::RenderOperation::OT_LINE_LIST);
	mo->position(0,10000,0);
	mo->colour(ColourValue(.2,1,.2,.5));
	mo->position(0,-10000,0);
	mo->colour(ColourValue(.2,1,.2,.5));
	mo->end();

	mLineHelpers->attachObject(mo);

	mo =  mSceneMgr->createManualObject("LineHelper_Z");
	mo->setCastShadows(false);
	mo->setDynamic(true);
	mo->estimateVertexCount(2);
	mo->estimateIndexCount(2);

	mo->begin("VertexColour/Flat/AlphaBlended/NoCull", Ogre::RenderOperation::OT_LINE_LIST);
	mo->position(0,0,10000);
	mo->colour(ColourValue(.2,.2,1,.5));
	mo->position(0,0,-10000);
	mo->colour(ColourValue(.2,.2,1,.5));
	mo->end();

	mLineHelpers->attachObject(mo);
	//}}}

	//{{{ Plane
//	Plane plane;
//	plane.normal = mCamera->getDerivedDirection();
//	plane.d=0;
//	mPlane = new MovablePlane(plane);
//	Ogre::MeshManager::getSingleton().createPlane("TFW_Plane",
//	        Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
//	        10, 10, 1, 1, true, 1, 1, 1, Ogre::Vector3::UNIT_Y);
//	mPlaneEnt = mSceneMgr->createEntity( "TFW_Plane_Entity", "TFW_Plane" );
//	mPlaneEnt->setMaterialName("PlaneGrid");
//	mPlaneEnt->setCastShadows(false);
//
//	mPlaneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("TFW_Plane_Node");
//	mPlaneNode->attachObject(mPlaneEnt);
//	mPlaneNode->attachObject(mPlane);
//	mPlaneNode->setVisible(false);
	//}}}

	//{{{ Overlay
	OverlayManager& olm = OverlayManager::getSingleton();

//	mNode->setPosition(0,0,-30);

	Ogre::OverlayContainer* panelW = static_cast<OverlayContainer*>(olm.createOverlayElement("Panel", "OverlayFix"));
	panelW->setMetricsMode(Ogre::GMM_RELATIVE);
	panelW->setPosition(0,0);
	panelW->setDimensions(1,1);
//	panelW->setParameter("transparent","true");
	panelW->setMaterialName("OverlayFix");

	Ogre::Overlay* overlayw = olm.create("OverlayFix");
	overlayw->add2D(panelW);
	overlayw->setZOrder(99);
	overlayw->show();

	mOverlay = olm.create("TransformWidget_Overlay");
	mOverlay->setZOrder(100);
	mOverlay->setScroll(0,0);
	mOverlay->add3D(mNode);
//	mOverlay->show();
	//}}}
}


TransformWidget::~TransformWidget()
{
	_clear();

	mScaleNodes.clear();
	mMoveNodes.clear();
	mRotateNodes.clear();

	mNode->detachAllObjects();

	Root::getSingletonPtr()->removeFrameListener(this);

	TransformWidget::mInit = false;
	TransformWidget::mInstance = 0;
//	delete TransformWidget::mInstance;
}

void TransformWidget::_setup()
{
	ProceduralPrimitiveFactory ppf(mSceneMgr);

	Real A = 0.05f;
	Real S = 35;

	ppf.createBox		("Center_Box", 	"VertexColour/CullNone", ColourValue::White, 1, 1, 1, 1, 1, 1, 1, 1);

	ppf.createCone		("X_Cone", 		"VertexColour/CullNone", ColourValue::Red, .75, 1.5, 1, 16, 1, 1);
	ppf.createBox		("X_Box", 		"VertexColour/CullNone", ColourValue::Red, 1, 1, 1, 1, 1, 1, 1, 1);
	ppf.createCylinder	("X_Cylinder", 	"VertexColourDepthOff",  ColourValue::Red, 6, .5, false, 1, S, 1, 1);
	ppf.createBox		("X_Line",		"VertexColour/CullNone", ColourValue::Red, 1, A, A, 1, 1, 1, 1, 1);

	ppf.createCone		("Y_Cone", 		"VertexColour/CullNone", ColourValue::Green, .75, 1.5, 1, 16, 1, 1);
	ppf.createBox		("Y_Box", 		"VertexColour/CullNone", ColourValue::Green, 1, 1, 1, 1, 1, 1, 1, 1);
	ppf.createCylinder	("Y_Cylinder",  "VertexColourDepthOff",  ColourValue::Green, 6, .5, false, 1, S, 1, 1);
	ppf.createBox		("Y_Line", 		"VertexColour/CullNone", ColourValue::Green, A, 1, A, 1, 1, 1, 1, 1);

	ppf.createCone		("Z_Cone", 		"VertexColour/CullNone", ColourValue::Blue, .75, 1.5, 1, 16, 1, 1);
	ppf.createBox		("Z_Box", 		"VertexColour/CullNone", ColourValue::Blue, 1, 1, 1, 1, 1, 1, 1, 1);
	ppf.createCylinder	("Z_Cylinder",  "VertexColourDepthOff",  ColourValue::Blue, 6, .5, false, 1, S, 1, 1);
	ppf.createBox		("Z_Line", 		"VertexColour/CullNone", ColourValue::Blue, A, A, 1, 1, 1, 1, 1, 1);

	ppf.createBox		("XY", 			"VertexColour/CullNone/AlphaBlended", ColourValue(.5,.5,.5,.5), 1, 1, .1, 1, 1, 1, 1, 1);
	ppf.createBox		("XZ", 			"VertexColour/CullNone/AlphaBlended", ColourValue(.5,.5,.5,.5), 1, .1, 1, 1, 1, 1, 1, 1);
	ppf.createBox		("YZ", 			"VertexColour/CullNone/AlphaBlended", ColourValue(.5,.5,.5,.5), .1, 1, 1, 1, 1, 1, 1, 1);

	mInit = true;
}

void TransformWidget::_clear()
{
	try
		{
			mSceneMgr->destroyEntity("X_Cone");
			mSceneMgr->destroyEntity("X_Box");
			mSceneMgr->destroyEntity("X_Cylinder");
			mSceneMgr->destroyEntity("X_Line");

			mSceneMgr->destroyEntity("Y_Cone");
			mSceneMgr->destroyEntity("Y_Box");
			mSceneMgr->destroyEntity("Y_Cylinder");
			mSceneMgr->destroyEntity("Y_Line");

			mSceneMgr->destroyEntity("Z_Cone");
			mSceneMgr->destroyEntity("Z_Box");
			mSceneMgr->destroyEntity("Z_Cylinder");
			mSceneMgr->destroyEntity("Z_Line");

			mSceneMgr->destroyEntity("XY");
			mSceneMgr->destroyEntity("XZ");
			mSceneMgr->destroyEntity("YZ");

			mSceneMgr->destroySceneNode("TransformWidget");
		}
	catch (Ogre::Exception& e)
		{
			cout << e.getDescription() << endl;
		}

//	if(mNode && mNode->numChildren()) {
//		mNode->removeAllChildren();
//		delete mNode;
//	}

//	delete mTransNode;
//	delete mGo;
}

void TransformWidget::onAxisPressed(unsigned int a)
{
//	mActiveAxis = n;

	SceneNode* node;
	Entity* ent;

	const Vector4 c(1.0, 1.0, 1.0, 1.0);

	static_cast<SceneNode*>(mNode->getChild("Center_Box"))->setVisible(false);

	mCircleNode->setVisible(mMode==ROTATE);

	Ogre::String nodeName;
	switch (a)
		{
		case X_AXIS:
			setNodesVisible("Y_*", false);
			setNodesVisible("Z_*", false);
			setNodesColour("X_*", c);
//			mTransVec = Vector3::UNIT_X;
			break;

		case Y_AXIS:
			setNodesVisible("X_*", false);
			setNodesVisible("Z_*", false);
			setNodesColour("Y_*", c);
//			mTransVec = Vector3::UNIT_Y;
			break;

		case Z_AXIS:
			setNodesVisible("X_*", false);
			setNodesVisible("Y_*", false);
			setNodesColour("Z_*", c);
//			mTransVec = Vector3::NEGATIVE_UNIT_Z;
			break;

		case (X_AXIS | Y_AXIS):
			setNodesVisible("Z_*", false);
			setNodesColour("X_*", c);
			setNodesColour("Y_*", c);
			setNodesColour("XY", c);
			break;

		case (X_AXIS | Z_AXIS):
			setNodesVisible("Y_*", false);
			setNodesColour("X_*", c);
			setNodesColour("Z_*", c);
			setNodesColour("XZ", c);
			break;

		case (Y_AXIS | Z_AXIS):
			setNodesVisible("X_*", false);
			setNodesColour("Y_*", c);
			setNodesColour("Z_*", c);
			setNodesColour("YZ", c);
			break;

		case (X_AXIS | Y_AXIS | Z_AXIS):
			node = static_cast<SceneNode*>(mNode->getChild("Center_Box"));
			node->setVisible(true);
			ent = static_cast<Entity*>(node->getAttachedObject(0));
			ent->setMaterialName("PlainColorNoCull");
			const_cast<SubEntity *>(ent->getSubEntity(0))->setCustomParameter(1, c);
//			mTransVec = Vector3::UNIT_SCALE;
			break;
		}

	if(mMode==MOVE && mTransNode!=0)
		{
			Quaternion q = Vector3::UNIT_Y.getRotationTo(mTransVec);
			if(mTS==LOCAL)
				q = mTransNode->getOrientation()*q;

			if(mActiveAxis==3)
				q = mCamera->getDerivedOrientation();

//			mPlaneNode->setPosition(mTransNode->getPosition());
//			mPlaneNode->setOrientation(q);
//			mPlaneNode->setVisible(true);
		}

	mTransforming = true;
}

void TransformWidget::onReleased()
{
	Entity* ent;
	SceneNode* node;

	mCircle->setVisible(false);

	// unhide & repaint all entities..
	for (std::vector<Entity*>::iterator it=mEntities.begin(); it!=mEntities.end(); ++it)
		{
			ent = static_cast<Entity*>(*it);
			if(StringUtil::match(ent->getName(), "*_Cylinder"))
				ent->setMaterialName("VertexColourDepthOff");
			else
				ent->setMaterialName("VertexColour/CullNone");
//			ent->setMaterialName("VertexColour/CullNone");
			ent->setVisible(true);

		}

//	mPlaneNode->setVisible(false);

	setMode(mMode);

	if(mMode==SCALE && mActiveAxis>=0 && mActiveAxis<=2)
		mScaleNodes[mActiveAxis]->translate(-mOffset);

	mActiveAxis=-1;
	mOffset = Vector3::ZERO;

	mTransforming = false;
	mTransVec = Vector3::ZERO;

//	mNode->setOrientation(Quaternion::IDENTITY);

	if (mGo==NULL) return;

	switch(mMode)
		{
		case SCALE:
			break;
		case MOVE:
			for(std::vector<SceneNode*>::iterator it = mMoveNodes.begin(); it != mMoveNodes.end(); it++, node = (*it))
				{
					node = static_cast<Ogre::SceneNode*>(*it);
					node->setVisible(true);
				}
			break;
		case ROTATE:
			for(std::vector<SceneNode*>::iterator it = mRotateNodes.begin(); it != mRotateNodes.end(); it++, node = (*it))
				{
					node = static_cast<Ogre::SceneNode*>(*it);
					node->setVisible(true);
				}
			break;
		}


}

bool TransformWidget::frameEnded(const FrameEvent& evt)
{
	return true;
}

bool TransformWidget::frameRenderingQueued(const FrameEvent& evt)
{
	return true;
}

bool TransformWidget::frameStarted(const FrameEvent& evt)
{
	if(mCamera==NULL || mNode==NULL) return true;
	if(mGo==NULL) return true;

	Vector3 	camPos = mCamera->getDerivedPosition();
	Quaternion 	camOrient = mCamera->getDerivedOrientation();
	Quaternion 	invCamOrient = camOrient.Inverse();

	SceneNode* node = mGo->getProperty<SceneNode*>("scenenode");

	if(mTS==VIEW)
		mNode->setOrientation(Quaternion::IDENTITY);
	else if(mTS==WORLD)
		{
			mNode->setOrientation(invCamOrient);
			mCircleNode->setOrientation(camOrient);
			mCircleNode->pitch(Degree(90));
		}
	else if(mTS==LOCAL)
		{
			mNode->setOrientation(invCamOrient*node->getOrientation());
			mCircleNode->setOrientation(camOrient*node->getOrientation().Inverse());
			mCircleNode->pitch(Degree(90));
		}


	Vector3 p;
	AxisAlignedBox bb = mGroup.getBoundingBox();
	if(bb.isNull() || bb.isInfinite())
		p = node->getPosition();
	else
		p = mGroup.getBoundingBox().getCenter();

	if(p.isNaN() || p.isZeroLength()) return true;

	mNode->setPosition(invCamOrient*(p - mCamera->getDerivedPosition()));

	Vector3 v = invCamOrient*camPos - invCamOrient*p;
	Real s = v.length() / 30.f;
	if(Math::isNaN(s)) return true;
	mNode->setScale(s*Vector3::UNIT_SCALE);

//	mNode->_update(true, true);

	return true;
}

void TransformWidget::onMouseMove(const OIS::MouseEvent& e)
{
	if (!mTransforming) return;
	if (!mCamera || !mNode) return;
	if (!mTransNode) return;
//	if(mActiveAxis<0) return;

	const OIS::MouseState& ms = e.state;
	Vector3 dm(ms.X.rel,-ms.Y.rel,-ms.X.rel);
	Vector3 mRel(ms.X.rel,-ms.Y.rel, 0);

	Real x = ms.X.abs / float(ms.width);
	Real y = ms.Y.abs / float(ms.height);
	Real z = 1 - x*x - y*y;
	z = z > 0 ? Math::Sqrt(z) : 0;

	Vector3 DeltaMouse = Vector3(x, y, z);

	OIS::Keyboard* keyb = InputManager::getSingletonPtr()->getKeyboard();
	bool slow = keyb->isModifierDown(OIS::Keyboard::Shift);

	Ray ray = mCamera->getCameraToViewportRay(x,y);

	switch(mMode)
		{
		case SCALE:
		{
			Vector3 u = 0.0033*mTransVec*dm;
			mTransNode->scale(Vector3::UNIT_SCALE + u);

			if(mActiveAxis>=0 && mActiveAxis<=2)
				{
					mScaleNodes[mActiveAxis]->translate(5*u);
					mOffset += 5*u;
				}

			if (!mGo) return;

			::Object trans = mGo->getProperty< ::Object>("transform");
			prop_cast<Vector3>(trans["scale"])->Set(mTransNode->getScale());
		}
		break;
		case MOVE:
		{
			Vector3 nodePos = mTransNode->getPosition();
			Quaternion nodeOrient = mTransNode->getOrientation();

			Vector3 camPos = mCamera->getDerivedPosition();
			Vector3 camDir = mCamera->getDerivedDirection();
			Quaternion camOrient = mCamera->getDerivedOrientation();
			Matrix4 invViewProj = (mCamera->getProjectionMatrix() * mCamera->getViewMatrix()).inverse();

			Plane cameraPlane = Plane(camDir, camPos);

			Vector3 v = nodePos - camPos;
			Real d = (slow ? .1f : 1) * .33f*Math::Exp(-2)/Math::PI*v.length();

			Vector3 u = mActiveAxis==3 ?
			            0.1*cameraPlane.projectVector(mRel) :
			            .03f*d*mTransVec*dm*(invViewProj*ray.getDirection());

			GameObjectGroup::GameObjectIterator it = mGroup.getObjectIterator();
			while(it.hasMoreElements())
				{
					BaseGameObject* go = it.getNext();
					SceneNode* node = go->getProperty<SceneNode*>("scenenode");

					if(mTS==VIEW)
						{
						}

					if(mTS==LOCAL)
						node->translate(u, Node::TS_LOCAL);

					if(mTS==WORLD)
						node->translate(u, Node::TS_WORLD);

					::Object trans = go->getProperty< ::Object>("transform");
					prop_cast<Vector3>(trans["pos"])->Set(node->getPosition());
				}
		}
		break;
		case ROTATE:
		{
			Quaternion nodeOrient = mTransNode->getOrientation();
			Quaternion q;
			Quaternion dq;
			Degree d = Degree((slow ? .1f : 1) * dm.length());
			if(mTransVec==Vector3::UNIT_X)
				q.FromAngleAxis(0.33*dm.x*d, Vector3::UNIT_Y);

			if(mTransVec==Vector3::UNIT_Y)
				q.FromAngleAxis(-0.33*dm.y*d, Vector3::UNIT_X);

			if(mTransVec==Vector3::NEGATIVE_UNIT_Z)
				q.FromAngleAxis(-0.33*dm.x*d, Vector3::UNIT_Z);

			GameObjectGroup::GameObjectIterator it = mGroup.getObjectIterator();
			while(it.hasMoreElements())
				{
					BaseGameObject* go = it.getNext();
					SceneNode* node = go->getProperty<SceneNode*>("scenenode");

					if(mTS==WORLD)
						node->rotate(q, Node::TS_WORLD);

					if(mTS==LOCAL)
						node->rotate(q, Node::TS_LOCAL);

					::Object trans = go->getProperty< ::Object>("transform");
					prop_cast<Quaternion>(trans["orientation"])->Set(node->getOrientation());
				}


			dq = mNode->getOrientation() - nodeOrient;

			const int accuracy = 35;
			const int radius = 6.1;
			unsigned point_index = 0;
			float deltaAngle = (dq.getRoll().valueRadians()*Ogre::Math::PI / accuracy);

			if(mActiveAxis>=0 && mActiveAxis<=2)
				mCircle->setVisible(true);

			mCircle->beginUpdate(0);

			mCircle->position(0,.25,0);
			mCircle->colour(ColourValue(.5,.5,.5,.5));
			point_index++;
			for (int j=0; j<=accuracy; j++)
				{
					float x0 = radius * cosf(j*deltaAngle);
					float z0 = radius * sinf(j*deltaAngle);

					if(mActiveAxis==0)
						mCircle->position(x0, 0.25f, z0);
					else if(mActiveAxis==1)
						mCircle->position(0.25f, x0, z0);
					else if(mActiveAxis==2)
						mCircle->position(x0, z0, 0.25f);

					if (j!=accuracy)
						{
							mCircle->index(0);
							mCircle->index(point_index);
							mCircle->index(point_index+1);
						}
					point_index++;
				}

			mCircle->end();
		}
		break;
		}
	mNode->_update(true, true);
}

void TransformWidget::setMode(Mode m)
{
	mMode = m;

	std::vector<SceneNode*>::iterator it;
	SceneNode* node = NULL;

	for(it = mMoveNodes.begin(); it != mMoveNodes.end(); it++, node = (*it))
		{
			node = static_cast<Ogre::SceneNode*>(*it);
			node->setVisible(m==MOVE);
		}
	for(it = mScaleNodes.begin(); it != mScaleNodes.end(); it++, node = (*it))
		{
			node = static_cast<Ogre::SceneNode*>(*it);
			node->setVisible(m==SCALE);
		}
	for(it = mRotateNodes.begin(); it != mRotateNodes.end(); it++, node = (*it))
		{
			node = static_cast<Ogre::SceneNode*>(*it);
			node->setVisible(m==ROTATE);
		}
	for(it = mLineNodes.begin(); it != mLineNodes.end(); it++, node = (*it))
		{
			node = static_cast<Ogre::SceneNode*>(*it);
			node->setVisible(m!=ROTATE);
		}

	mCircleNode->setVisible(m==ROTATE);
}

void TransformWidget::setNodesVisible(const Ogre::String& match, bool visible)
{
	SceneNode::ChildNodeIterator it = mNode->getChildIterator();
	SceneNode* node;

	while (it.hasMoreElements())
		{
			node = static_cast<SceneNode*>(it.getNext());
			if(StringUtil::match(node->getName(), match))
				node->setVisible(visible);
		}
}



void TransformWidget::setNodesColour(const Ogre::String& match, Vector4 col)
{
	SceneNode::ChildNodeIterator it = mNode->getChildIterator();
	SceneNode* node;
	Entity* ent;

	while (it.hasMoreElements())
		{
			node = static_cast<SceneNode*>(it.getNext());
			if(!StringUtil::match((node)->getName(), match)) continue;
			ent = static_cast<Entity*>((node)->getAttachedObject(0));
			ent->setMaterialName("PlainColorNoCull");
			const_cast<SubEntity *>(ent->getSubEntity(0))->setCustomParameter(1, col);
		}

}

void TransformWidget::onEntityPressed(Ogre::Entity* ent)
{
	unsigned int axis = mEntAxisMap[ent];
	onAxisPressed(axis);
	mAxes = axis;
	mTransVec = Vector3(
	                (mAxes & X_AXIS) == 0x000 ? 0 : 1,
	                (mAxes & Y_AXIS) == 0x000 ? 0 : 1,
	                (mAxes & Z_AXIS) == 0x000 ? 0 : 1
	            );
}
